package agent;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;

import jade.core.behaviours.Behaviour;
import jade.core.behaviours.CyclicBehaviour;
import jade.core.behaviours.SequentialBehaviour;
import dao.DaoAgente;
import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.*;
import jade.lang.acl.ACLMessage;
import model.Coordenada;
import model.Stop;


public class AgCoordenador extends Agent {

	private Coordenada origem;
	private Coordenada destino;
	protected ArrayList<Stop> stopsOrigem;
	private int numStops = 0;
//	private int numAvisos = 0;
	
	private static final long serialVersionUID = 1L;
	
	protected void setup(){
		
		//monta objeto dos argumentos
		Object[] args = getArguments();
		if(args != null && args.length > 0){
			this.origem = (Coordenada)args[0];
			this.destino = (Coordenada)args[1];
			this.stopsOrigem = new ArrayList<Stop>();
			System.out.println("Argumento :"+args[0]);
//			if(numStops == 0){
				SequentialBehaviour seq = new SequentialBehaviour(this){//Comportamento composto
					
					private static final long serialVersionUID = 1L;
					
					public int onEnd(){
						block();
						//myAgent.doDelete();
						return 0;
					}
					
				};
				
				
				
				
				seq.addSubBehaviour(new Behaviour(this){ //comportamento de busca stops iniciais
					int raioOrigem = 0;
					DaoAgente dao = new DaoAgente();
					String msg = "";
					
					//executado enquanto done() retorne false
					public void action() {
						System.out.println("Exec comportamento...BUSCA SOTOP"+myAgent.getName());
						raioOrigem++;
						stopsOrigem = dao.getStopsOfCoordRaio(origem.getLat(), origem.getLon(), raioOrigem);
					}
					
					//Se retornar true o comportamento e finalizado
					public boolean done() {
						if(stopsOrigem.size()>0){
							System.out.println("Acchei "+stopsOrigem.size()+" pontos em raio = "+raioOrigem);
							numStops = stopsOrigem.size();
							return true;
						}
						for(int i=0; i<stopsOrigem.size(); i++){
							double distStop = destino.calculaDistancia(stopsOrigem.get(i).getStop_lat(), stopsOrigem.get(i).getStop_lon());
							if(distStop <= 1000){
								System.out.println("Raio origem proximo do destino...");
								//====================Falta finalizar agente para este caso
								return true;
							}
							
						}
						double distOrgDstn = origem.calculaDistancia(destino.getLat(),destino.getLon());
						if(distOrgDstn <= 600){
							System.out.println("Destino proximo demais da origem...");
							//========================Falta finalizar agente para este caso
							return true;
						}
						return false;
					}
					
				});//fim do comportamento de busca stops iniciais
				
				
				seq.addSubBehaviour(new Behaviour(this){ //Busca serviço no DFD e envia mensagem
					int cont = 0;
					public void action() {
						//Cria entrada no DF
						DFAgentDescription template = new DFAgentDescription();
						
						//objeto contendo descrição do servço
						ServiceDescription sd = new ServiceDescription();
						sd.setType("busca");
						sd.setName("buscarota");
						//adiciona serviço a endtrada
						template.addServices(sd);
						//inicia busca
						try{
							//recupera tabela de agentes que oferecem o serviço buscado
							DFAgentDescription[]  result  = DFService.search(myAgent,template);
							
							System.out.println("Numero de agentes na tabela = "+result.length);
							
							if(result.length >0){
								int i = 0;
								while( i < result.length && cont < stopsOrigem.size()){
									
									//monta obj para envio
									Hashtable obj = new Hashtable();
									obj.put("origem", origem);
									obj.put("destino", destino);
									System.out.println("Enviando stop num = "+(cont+1)+" - "+stopsOrigem.get(cont).getStop_id()+" ao agente "+result[i].getName().getLocalName());
									obj.put("stopOrigem", stopsOrigem.get(cont));
									
									//envia um mensagem com obj para  o agente da tabela
									ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
									msg.addReceiver(new AID(result[i].getName().getLocalName(), AID.ISLOCALNAME));
									msg.setContent("stopOrigem");
									msg.setContentObject(obj);
									myAgent.send(msg);
									++cont;
									++i;
									try {
										Thread.sleep(500);
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
								}
							}
							
						}catch(FIPAException e){
							System.out.println("ERRO DE FIPAException");
							e.printStackTrace();
						}catch(IOException e){
							System.out.println("ERRO DE IOException");
							e.printStackTrace();
						}
						
						
					}
					
					
					public boolean done() {
						
						return (cont >= stopsOrigem.size());
					}
					
				});//fim do Busca serviço no DFD e envia mensagem
				
				//Adicionando comportamento sequencial ao comportamento
				addBehaviour(seq);  
				
//			} // fim do if numero de stops
		}
		else{
			System.out.println("Sem argumentos...");
			doDelete();
		}
		
		
		
//		addBehaviour(new CyclicBehaviour(this){ //recebe mensagen com aviso de termino do agente buscador
//			
//			private static final long serialVersionUID = 1L;
//			
//			
//			public void action(){
//				
//				//System.out.println(myAgent.getName()+" Exec comportamento...RECEBE MSG DE RETORNO...");
//				ACLMessage msg = myAgent.receive();
//				if(msg != null){
//					System.out.println("RECEBENDO MSG DE RETORNO DO AGENTE "+msg.getSender().getName());
//					String content = msg.getContent();
//					if(content.equalsIgnoreCase("terminado")){
//						++numAvisos;
//						System.out.println("Num avisos = "+numAvisos);
//						
//						//respondendo
//						ACLMessage reply = msg.createReply();
//						reply.setPerformative(ACLMessage.INFORM);
//						reply.setContent("msgrecebida");
//						myAgent.send(reply);
//					}
//				}else{
//					block();
//				}
//				
//				if(numAvisos == numStops){
//					AreaRotas.setTerminou(true);
//					myAgent.doDelete();
//				}
//			}
//		});//fim do recebe mensagem
		
		
		
		addBehaviour(new Behaviour(this){ //Verifica status das rotas
			private static final long serialVersionUID = 1L;
			int numeroBuscas = AreaRotas.getNumBuscas();
			
			public void action(){
				
				if(numeroBuscas == numStops){
					AreaRotas.setTerminou(true);
				}
				
			}
			public boolean done(){
				return numeroBuscas == numStops;
			}
		});//fim do Verifica staaus das rotas
		
		
	}
	 
	protected void takeDown(){
		System.out.println("########### Agente coordenador fianlizado #############");
	}

}
